#include "Validator.h"

namespace Validator
{


using namespace std;

Validator::Validator(std::string theSchemeFilesPath)
{
	boost::filesystem::path aDirPath(theSchemeFilesPath);
	boost::filesystem::directory_iterator dirIter(aDirPath);
	boost::filesystem::directory_iterator dirEnd;

	while( dirIter != dirEnd)
	{
		if( boost::filesystem::is_regular(dirIter->status()))
		{
			size_t index = dirIter->filename().rfind(".xml");
			if(index != string::npos)
			{
				mySchemeFiles.push_back(dirIter->path());
			}
		}
		dirIter++;
	}
}


Validator::~Validator(void)
{}

void Validator::Init(void)
{
	if(mySchemeFiles.size() == 0 )
		return;

	for(unsigned int i=0; i < mySchemeFiles.size(); i++)
	{
		try
		{
			mySchemes.push_back(Parse(mySchemeFiles[i].file_string()));
		}
		catch(InvalidXMLFormatException)
		{
			continue;
		}
	}
}


boost::optional<Scheme> Validator::GetScheme(std::string theSchemeName)
{
	vector<Scheme>::iterator aResult;
	SchemeMatch aMatch(theSchemeName);
	aResult = find_if(mySchemes.begin(), mySchemes.end(),aMatch);
	if(aResult != mySchemes.end())
	{
		return boost::optional<Scheme>(*aResult);
	}

	return boost::optional<Scheme>();
}

//******************************************************************//
//						Private Methods								//
//******************************************************************//

bool Validator::MatchScheme(Scheme theScheme,std::string theSchemeName)
{
	if(theScheme.GetName() == theSchemeName)
		return true;

	return false;
}


Scheme Validator::Parse(string theFile)
{
	string schemeName;
	string schemeArchivType;
	TiXmlDocument xmlDoc(theFile);

	if(!xmlDoc.LoadFile())
	{
		throw exception();
	}

	TiXmlHandle handleDoc(&xmlDoc);
	TiXmlElement *pElem;
	TiXmlElement *pRootElem;
	TiXmlHandle handleRoot(0);


	pElem = handleDoc.FirstChildElement().ToElement();

	if(pElem == NULL)
	{
			throw InvalidXMLFormatException("Possibly not an XML file!");
	}

	string theElemValue = pElem->Value();

	if(theElemValue != "archiv")
	{
			throw InvalidXMLFormatException("Missing or wrong root node!");
	}

	schemeName = pElem->Attribute("class");
	schemeArchivType = pElem->Attribute("type");
	if(schemeName.empty() || schemeArchivType.empty() )
	{
			throw InvalidXMLFormatException("Empty root attributes!");
	}

	//vytvorime si Schemu
	Scheme aScheme(schemeName,schemeArchivType.c_str());


	pRootElem = pElem;

	//citanie adresarov nachadzajucich sa v koreni
	handleRoot = TiXmlHandle(pRootElem);
	pElem = handleRoot.FirstChild("directory").Element();
	for(pElem;pElem;pElem=pElem->NextSiblingElement())
	{
		string dirName = pElem->Attribute("name");
		if(dirName.empty())
		{
			throw InvalidXMLFormatException("Missing or wrong directory name attribute!");
		}
		aScheme.Add(ParseDirectory(pElem));
	}

	//citanie suborov nachadzajucich sa v koreni
	handleRoot = TiXmlHandle(pRootElem);
	pElem = handleRoot.FirstChild("file").Element();
	for(pElem;pElem;pElem=pElem->NextSiblingElement())
	{
		aScheme.Add(ParseFile(pElem));
	}

	return aScheme;
}

MetaFile Validator::ParseFile(TiXmlElement *pElem)
{
		bool doExtract = false;
		const char* fileType = pElem->Attribute("type");
		const char* fileDoExtract = pElem->Attribute("extract");
		string fileName = pElem->GetText();
		if(fileDoExtract != NULL)
		{
			if(strcmp(fileDoExtract,"true") == 0 )
			{
					doExtract = true;
			}
		}
		MetaFile aFile(fileName,fileType,doExtract);
		return aFile;
}

MetaDirectory Validator::ParseDirectory(TiXmlElement *pElem)
{
		TiXmlHandle theHandle(pElem);
		vector<MetaFile> aFileColl;
		vector<MetaDirectory> aDirColl;
		string dirName;
		bool anyFlag = false;

		dirName = pElem->Attribute("name");
		TiXmlElement *pElemIn =  pElem->FirstChildElement("directory");
		if(pElemIn != NULL)
		{
				for(pElemIn;pElemIn;pElemIn=pElemIn->NextSiblingElement())
				{
					MetaDirectory  aResult = ParseDirectory(pElemIn);
					aDirColl.push_back(aResult);
				}
		}
		else if( (pElemIn = theHandle.FirstChildElement("file").ToElement()) != NULL)
		{
				aFileColl.push_back(ParseFile(pElemIn));
		}
		else
		{
				anyFlag = true;
		}


		MetaDirectory aDir(dirName,aFileColl,aDirColl,anyFlag);
		return aDir;
}

}